package org.linloong.modules.apis.monitor.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.linloong.modules.apis.monitor.dto.BarEchartsDataDTO;
import org.linloong.modules.apis.monitor.dto.BarHomeDataDTO;
import org.linloong.modules.apis.monitor.dto.DeviceInfoDTO;
import org.linloong.modules.apis.monitor.entity.*;
import org.linloong.modules.apis.monitor.enums.HabitatEnum;
import org.linloong.modules.apis.monitor.dto.LineEchartsDataDTO;
import org.linloong.modules.apis.monitor.mapper.*;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class DataMonitorService {

    private final WeatherDataParsedMapper weatherDataParsedMapper;
    private final DeviceInfoMapper deviceInfoMapper;
    private final NnWeatherDataMapper nnWeatherDataMapper;
    private final WeatherDataMapper weatherDataMapper;
    private final DeviceGroupMapper deviceGroupMapper;
    private final RealTimeDataService realTimeDataService;

    private static final DateTimeFormatter FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                    .withZone(ZoneId.systemDefault());

    /**
     * 10分钟一条数据，近12条数据
     * @param type
     * @param limit
     * @return
     */
    public LineEchartsDataDTO getHabitatDataByType(String type, Integer limit) {
        DeviceGroup deviceGroup = deviceGroupMapper.selectOne(Wrappers.<DeviceGroup>lambdaQuery()
                .eq(DeviceGroup::getGroupName, "生境"));
        List<WeatherDataParsed> list = new ArrayList<>();
        if(ObjectUtils.isEmpty(deviceGroup)){
            return LineEchartsDataDTO.builder()
                    .build()
                    .init("", "", limit, 10L);
        }
        HabitatEnum habitatEnum = HabitatEnum.ofCode(type);
        if (ObjectUtils.isEmpty(habitatEnum )) {
            return LineEchartsDataDTO.builder()
                    .build()
                    .init("", "", limit, 10L);
        }
        list = weatherDataParsedMapper.selectList(
                Wrappers.<WeatherDataParsed>lambdaQuery()
                        .in(WeatherDataParsed::getDeviceId, deviceGroup.getDeviceIds())
                        .eq(WeatherDataParsed::getSensorName, habitatEnum.getName())
                        .orderByDesc(WeatherDataParsed::getTimestamp)
                        .last("limit " + limit));
        List<LineEchartsDataDTO.LineData> lineList = new ArrayList<>(limit);
        if (ObjectUtils.isEmpty(list)) {
            return LineEchartsDataDTO.builder()
                    .build()
                    .init(habitatEnum.getName(), habitatEnum.getUnit(), limit, 10L);
        }
        // 根据timestamp判断list中的数据是否连续，如果不连续，中间用null填充
        // 十分钟，timestamp间隔为600000毫秒
        Long lastTimestamp = list.get(0).getTimestamp();
        lineList.add(new LineEchartsDataDTO.LineData(
                FORMATTER.format(Instant.ofEpochMilli(lastTimestamp)),
                String.valueOf(list.get(0).getParsedValue())));
        for (int i = 0; i < limit - 1; i++) {
            lastTimestamp -= 600000L;
            LineEchartsDataDTO.LineData lineData = null;
            for (WeatherDataParsed data : list) {
                if(data.getTimestamp().equals(lastTimestamp) ){
                    lineData = new LineEchartsDataDTO.LineData(
                            FORMATTER.format(Instant.ofEpochMilli(lastTimestamp)),
                            String.valueOf(data.getParsedValue()));
                    break;
                }
            }
            if (lineData == null) {
                lineData = new LineEchartsDataDTO.LineData(
                        FORMATTER.format(Instant.ofEpochMilli(lastTimestamp)),
                        String.valueOf(0));
            }
            lineList.add(lineData);
        }
        Collections.reverse(lineList);
        return LineEchartsDataDTO.builder()
                .type(habitatEnum.getName())
                .unit(habitatEnum.getUnit())
                .data(lineList)
                .build();
    }

    public List<BarEchartsDataDTO> getBarData() {
        List<NnWeatherData> list = nnWeatherDataMapper.selectList(Wrappers.<NnWeatherData>lambdaQuery().last("order by date asc"));
        // 根据list的year进行分组，map
        Map<String, List<NnWeatherData>> map = list.stream()
                .collect(Collectors.groupingBy(NnWeatherData::getYear));
        List<BarEchartsDataDTO> barList = new ArrayList<>();
        for(Map.Entry<String, List<NnWeatherData>> entry : map.entrySet()){
            barList.add(BarEchartsDataDTO.builder()
                    .type(HabitatEnum.AIR_TEMPERATURE.getCode())
                    .unit(HabitatEnum.AIR_TEMPERATURE.getUnit())
                    .year(entry.getKey())
                    .data(entry.getValue().stream()
                            .map(item -> new BarEchartsDataDTO.BarData(
                                    item.getMonth(),
                                    item.getPjWd()))
                            .collect(Collectors.toList()))
                    .build());
            barList.add(BarEchartsDataDTO.builder()
                    .type(HabitatEnum.AIR_HUMIDITY.getCode())
                    .unit(HabitatEnum.AIR_HUMIDITY.getUnit())
                    .year(entry.getKey())
                    .data(entry.getValue().stream()
                            .map(item -> new BarEchartsDataDTO.BarData(
                                    item.getMonth(),
                                    item.getPjSd()))
                            .collect(Collectors.toList()))
                    .build());

            barList.add(BarEchartsDataDTO.builder()
                    .type(HabitatEnum.MIN_RAINFALL.getCode())
                    .unit(HabitatEnum.MIN_RAINFALL.getUnit())
                    .year(entry.getKey())
                    .data(entry.getValue().stream()
                            .map(item -> new BarEchartsDataDTO.BarData(
                                    item.getMonth(),
                                    item.getPjJy()))
                            .collect(Collectors.toList()))
                    .build());
        }
        return barList;
    }

    /**
     * 获取近三年当月数据，并按指标类型聚合
     * @return 按指标类型聚合的数据列表
     */
    public List<BarHomeDataDTO> getBarHomeData() {
        // 获取当前年份
        int currentYear = LocalDate.now().getYear();

        // 计算近三年的年份范围
        List<String> lastThreeYears = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            lastThreeYears.add(String.valueOf(currentYear - i));
        }

        // 获取当前月份
        String currentMonth = String.format("%02d", LocalDate.now().getMonthValue());

        // 查询近三年当月的数据
        List<NnWeatherData> list = nnWeatherDataMapper.selectList(
                Wrappers.<NnWeatherData>lambdaQuery()
                        .in(NnWeatherData::getYear, lastThreeYears)
                        .eq(NnWeatherData::getMonth, currentMonth)
                        .orderByAsc(NnWeatherData::getYear)
        );

        // 按指标类型分组处理数据
        Map<HabitatEnum, List<BarHomeDataDTO.BarData>> groupedByType = new HashMap<>();
        
        // 为每个年份创建数据
        for (NnWeatherData data : list) {
            String year = data.getYear();
            
            // 空气温度
            groupedByType.computeIfAbsent(HabitatEnum.AIR_TEMPERATURE, k -> new ArrayList<>())
                    .add(new BarHomeDataDTO.BarData(year,currentMonth, data.getPjWd()));
            
            // 空气湿度
            groupedByType.computeIfAbsent(HabitatEnum.AIR_HUMIDITY, k -> new ArrayList<>())
                    .add(new BarHomeDataDTO.BarData(year, currentMonth,data.getPjSd()));
            
            // 降雨量
            groupedByType.computeIfAbsent(HabitatEnum.MIN_RAINFALL, k -> new ArrayList<>())
                    .add(new BarHomeDataDTO.BarData(year, currentMonth,data.getPjJy()));
        }

        // 构建返回结果
        List<BarHomeDataDTO> result = new ArrayList<>();
        for (Map.Entry<HabitatEnum, List<BarHomeDataDTO.BarData>> entry : groupedByType.entrySet()) {
            HabitatEnum type = entry.getKey();
            List<BarHomeDataDTO.BarData> data = entry.getValue();
            
            result.add(BarHomeDataDTO.builder()
                    .type(type.getCode())
                    .unit(type.getUnit())
                    .data(data)
                    .build());
        }

        return result;
    }



    public String getPicUrl() {
        DeviceGroup deviceGroups = deviceGroupMapper.selectOne(new LambdaQueryWrapper<DeviceGroup>().eq(DeviceGroup::getGroupName, "物候"));
        PhenologyPlusData data = realTimeDataService.getLatestPhenologyPlusData(deviceGroups.getDeviceIds().split(",")[0]).block();
        return data != null ? data.getOriginalImagePath() : null;
    }

    public List<DeviceInfoDTO> getDevicesInfo() {
        DeviceGroup deviceGroups = deviceGroupMapper.selectOne(Wrappers.<DeviceGroup>lambdaQuery()
                .eq(DeviceGroup::getGroupName, "胸径"));
        List<String> ids = Arrays.stream(deviceGroups.getDeviceIds().split(",")).sorted().toList();
        LocalDateTime lastMonth = LocalDateTime.now().minusDays(1);
        Long timestamp = lastMonth.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        List<DeviceInfoDTO> list = new ArrayList<>();
        for (String id : ids) {
            WeatherData data = weatherDataMapper.selectOne(
                    Wrappers.<WeatherData>lambdaQuery()
                            .eq(WeatherData::getDeviceId, id)
                            .orderByDesc(WeatherData::getTimestamp)
                            .last("limit 1"));
            if (ObjectUtils.isNotEmpty(data) && data.getTimestamp() >= timestamp) {
                list.add(new DeviceInfoDTO(id, 0));
            } else {
                list.add(new DeviceInfoDTO(id, 1));
            }
        }
        return list;
    }

    /**
     * 一天两条数据，获取14条数据
     * @param id
     * @param limit
     * @return
     */
    public LineEchartsDataDTO getDeviceLineData(String id, Integer limit) {
        List<WeatherDataParsed> list = weatherDataParsedMapper.selectList(
                Wrappers.<WeatherDataParsed>lambdaQuery()
                        .in(WeatherDataParsed::getDeviceId, id)
                        .eq(WeatherDataParsed::getSensorName, "树木经围")
                        .orderByDesc(WeatherDataParsed::getTimestamp)
                        .last("limit " + limit));
        if (list == null || list.isEmpty()) {
            return LineEchartsDataDTO.builder()
                    .build()
                    .init("树木胸径", "mm", limit, 10L);
        }
        List<LineEchartsDataDTO.LineData> lineList = new ArrayList<>();
        Long lastTimestamp = list.get(0).getTimestamp();
        lineList.add(new LineEchartsDataDTO.LineData(
                FORMATTER.format(Instant.ofEpochMilli(lastTimestamp)),
                String.valueOf(getFormattedValue(list.get(0).getParsedValue()))));
        for (int i = 0; i < limit - 1; i++) {
            lastTimestamp -= 12*60*60*1000L;
            LineEchartsDataDTO.LineData lineData = null;
            for (WeatherDataParsed data : list) {
                if(data.getTimestamp().equals(lastTimestamp) ){
                    lineData = new LineEchartsDataDTO.LineData(
                            FORMATTER.format(Instant.ofEpochMilli(lastTimestamp)),
                            String.valueOf(getFormattedValue(data.getParsedValue())));
                    break;
                }
            }
            if (lineData == null) {
                lineData = new LineEchartsDataDTO.LineData(
                        FORMATTER.format(Instant.ofEpochMilli(lastTimestamp)),
                        String.valueOf(0));
            }
            lineList.add(lineData);
        }
        Collections.reverse(lineList);
        return LineEchartsDataDTO.builder()
                .type("树木胸径")
                .unit("mm")
                .data(lineList)
                .build();
    }

    private String getFormattedValue(BigDecimal value) {
        return value.divide(BigDecimal.valueOf(Math.PI), 2, RoundingMode.HALF_UP).toString();
    }
}
